#include "bank.h"

Bank :: Bank () {
	accounts = NULL;
	amounts = NULL;
	locks = NULL;
	num_accounts = 0;
	fail_count = 0;
}

Bank :: ~Bank () {
	for (int i = 0; i < num_accounts; i++) {
		pthread_mutex_destroy (& locks [i]);
	}

	delete [] locks;
}

void Bank :: action (int act, int amt, int acc, int thd, int num_tr) {
	// Check to make sure we're accessing a valid account
	if (acc >= num_accounts || acc < 0) {
		cout << "Error: account access is not valid" << endl;
		return;
	}

	// TODO: Code
	if (act == 0) {
		// Deposit action

		pthread_mutex_lock (& locks [acc]);
		//cout << "Thread: " << thd << " ";
		cout << "Acct (" << accounts [acc] << ") - Trans_id = " << num_tr;
		cout << " : deposit $" << amt << endl;

		// Just deposit the amount and report success
		amounts [acc] += amt;
		cout << "*** status [" << accounts [acc] << ":D] = success; balance = $" << amounts [acc] << endl << endl;
		fail_count = 0;

		pthread_mutex_unlock (& locks [acc]);

	} else if (act == 1) {
		// Withdraw action

		pthread_mutex_lock (& locks [acc]);
		//cout << "Thread: " << thd << " ";
		cout << "Acct (" << accounts [acc] << ") - Trans_id = " << num_tr;
		cout << " : withdraw $" << amt << endl;

		// Check to make sure we have enough
		if (amounts [acc] > amt) {
			amounts [acc] -= amt;
			cout << "*** status [" << accounts [acc] << ":W] = success; balance = $" << amounts [acc] << endl << endl;
			fail_count = 0;
		} else {
			fail_count++;

			cout << "*** status [" << accounts [acc] << ":W] = denied (NSF); balance = $" << amounts [acc];

			if (fail_count == 2) {
				fail_count = 0;
				amounts [acc] -= 50;
				cout << "(Fees deducted: $50)";
			}

			cout << endl << endl;
		}

		pthread_mutex_unlock (& locks [acc]);
	} else {
		// Unknown action
		cout << "Error: action is not a withdraw or deposit: " << act << endl;
	}
}

void Bank :: set_accounts (int * accounts, int * amounts, int num_accounts) {
	this -> accounts = accounts;
	this -> amounts = amounts;

	if (this -> num_accounts != 0) {
		for (int i = 0; i < num_accounts; i++) {
			pthread_mutex_destroy (& locks [i]);
		}

		delete [] locks;
	}

	this -> num_accounts = num_accounts;
	locks = new pthread_mutex_t [num_accounts];


	for (int i = 0; i < num_accounts; i++) {
		pthread_mutex_init (& locks [i], NULL);
	}
}

